/**
 * BrandBigData.com Inc.
 * Copyright (c) 2016 All Rights Reserved.
 */
package com.qibao.toolkit.service;

import com.qibao.toolkit.exception.ExpressionExecuteException;
import com.qibao.toolkit.exception.ExpressionSyntaxException;
import com.qibao.toolkit.util.JsonUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.mvel2.MVEL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author xumin
 * @version $Id:ExpressionServiceImpl.java, v0.1 2017/6/16 10:42 xumin
 */
@Service
public class MVELExpressionService implements ExpressionService {
    private static final Logger logger = LoggerFactory.getLogger(MVELExpressionService.class);
    private Pattern pattern = Pattern.compile("(\\{[^{\\s]+\\})");

    @Override
    public String executeExpression(String expression, Map<String, Object> params) throws ExpressionExecuteException {
        if (StringUtils.isEmpty(expression)) {
            throw new ExpressionExecuteException("表达式不能为空");
        }
        List<String> variables = extractVariables(expression);
        for (String variable : variables) {
            expression = StringUtils.replace(expression, "{" + variable + "}", variable);
        }
        try {
            return MVEL.evalToString(expression, params);
        } catch (Throwable t) {
            logger.error("表达式执行失败，表达式：{} 参数：{}", expression, JsonUtils.writeValueAsString(params),t);
            throw new ExpressionExecuteException(t.getMessage());
        }
    }

    @Override
    public List<String> extractVariables(String expression) throws ExpressionSyntaxException {
        Matcher matcher = pattern.matcher(expression);
        Set<String> variables = Sets.newHashSet();
        while (matcher.find()) {
            String group = matcher.group();
            variables.add(group);
        }
        List<String> result = Lists.newArrayList();
        variables.forEach(variable -> result.add(StringUtils.substringBetween(variable, "{", "}")));
        return result;
    }

    @Override
    public boolean isValid(String expression) {
        if (StringUtils.isEmpty(expression)) {
            return false;
        }
        expression = StringUtils.remove(expression, '{');
        expression = StringUtils.remove(expression, '}');
        try {
            MVEL.compileExpression(expression);
            return true;
        } catch (Throwable t) {
            logger.warn("无效表达式(已经替换花括号)：{}", expression,t);
            return false;
        }
    }
}
